package martingale

import (
	"fmt"
	"math"
	"strings"
)

const (
	minBaseOrderUSD   = 12.0
	minGridSpacingPct = 0.3
	maxGridSpacingPct = 8.0
	minTakeProfitPct  = 0.3
	minStopLossPct    = 0.3
	maxStepsAllowed   = 8
	maxMultiplier     = 3.0
)

// UpdateParams 定义更新步骤的参数
type UpdateParams struct {
	StepIndex int     `json:"step_index"`
	NewPrice  float64 `json:"new_price"`
}

// Config定义AI提供的马丁格尔参数
type Config struct {
	Symbol         string  `json:"symbol"`
	Side           string  `json:"side"`
	BaseOrderUSD   float64 `json:"base_order_usd"`
	Multiplier     float64 `json:"multiplier"`
	MaxSteps       int     `json:"max_steps"`
	GridSpacingPct float64 `json:"spacing"`
	TakeProfitPct  float64 `json:"take_profit"`
	StopLossPct    float64 `json:"stop_loss"`
	Leverage       int     `json:"leverage"`
	MaxTotalUSD    float64 `json:"max_total_usd"`
	CooldownMin    int     `json:"cooldown_minutes"`
	Loop           bool    `json:"loop"` // 是否自动循环

	// 更新相关参数
	Action  string         `json:"action,omitempty"`  // "create" (默认) 或 "update"
	Updates []UpdateParams `json:"updates,omitempty"` // 仅当 Action="update" 时有效
}

func (c *Config) Normalize(defaultLeverage int) error {
	c.Symbol = strings.ToUpper(strings.TrimSpace(c.Symbol))
	if c.Symbol == "" {
		return fmt.Errorf("symbol is required")
	}

	c.Side = strings.ToLower(strings.TrimSpace(c.Side))
	if c.Side != "long" && c.Side != "short" {
		return fmt.Errorf("side must be long/short")
	}

	if c.BaseOrderUSD < minBaseOrderUSD {
		return fmt.Errorf("base_order_usd must be ≥ %.0f", minBaseOrderUSD)
	}

	if c.Multiplier == 0 {
		c.Multiplier = 2.0
	}
	if c.Multiplier < 1.05 {
		return fmt.Errorf("multiplier must be > 1.05")
	}
	if c.Multiplier > maxMultiplier {
		c.Multiplier = maxMultiplier
	}

	if c.MaxSteps <= 0 {
		c.MaxSteps = 3
	}
	if c.MaxSteps > maxStepsAllowed {
		c.MaxSteps = maxStepsAllowed
	}

	if c.GridSpacingPct <= 0 {
		c.GridSpacingPct = 0.8
	}
	if c.GridSpacingPct < minGridSpacingPct {
		c.GridSpacingPct = minGridSpacingPct
	}
	if c.GridSpacingPct > maxGridSpacingPct {
		c.GridSpacingPct = maxGridSpacingPct
	}

	if c.TakeProfitPct <= 0 {
		c.TakeProfitPct = 0.8
	}
	if c.TakeProfitPct < minTakeProfitPct {
		c.TakeProfitPct = minTakeProfitPct
	}

	if c.StopLossPct <= 0 {
		c.StopLossPct = 2.0
	}
	if c.StopLossPct < minStopLossPct {
		c.StopLossPct = minStopLossPct
	}

	if c.Leverage <= 0 {
		c.Leverage = defaultLeverage
	}

	if c.MaxTotalUSD > 0 && c.MaxTotalUSD < c.BaseOrderUSD {
		return fmt.Errorf("max_total_usd must be >= base_order_usd")
	}

	if c.CooldownMin < 0 {
		c.CooldownMin = 0
	}

	return nil
}

func (c Config) EstimatedExposure() float64 {
	total := 0.0
	remaining := c.MaxTotalUSD
	capped := remaining > 0
	size := c.BaseOrderUSD

	for i := 0; i < c.MaxSteps; i++ {
		if capped && remaining <= 0 {
			break
		}
		chunk := size
		if capped && chunk > remaining {
			chunk = remaining
		}
		total += chunk
		if capped {
			remaining -= chunk
		}
		size *= c.Multiplier
	}

	if capped {
		return math.Min(total, c.MaxTotalUSD)
	}
	return total
}
